﻿
using B.MES.SLY.Domain.Entities;
using EquipmentManagement.ApiHost.Url;
using EquipmentManagement.Domain.Entities;
using Infrastructure;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using Newtonsoft.Json;
using NPOI.SS.Formula.Functions;
using RBAC_Application.Dto.Output;
using SqlSugar;
using Standard;
using System.Net.Http;
using System.Transactions;
using Yitter.IdGenerator;

namespace EquipmentManagement.ApiHost.Controllers
{
    /// <summary>
    /// 数据字典
    /// </summary>
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class DataDictionaryController : ControllerBase
    {
        private readonly RedisDataDictionaryService _redisService;
        private readonly ISqlSugarClient _db;
        private readonly IDistributedCache _cache;
        private readonly HttpClient _httpClient;
        private readonly MesRepository<DataDictionary> _mesRepository;

        public DataDictionaryController(RedisDataDictionaryService redisService, ISqlSugarClient db, IDistributedCache cache, HttpClient httpClient, MesRepository<DataDictionary> mesRepository)
        {
            _redisService = redisService;
            _db = db;
            _cache = cache;
            _httpClient = httpClient;
            _mesRepository = mesRepository;
        }

        /// <summary>
        /// 数据字典redis缓存
        /// </summary>
        [HttpPost]
        public async Task<OkObjectResult> SetDict()
        {
            // 阶段1：数据库操作
            try
            {
                #region httpclint抓取数据车间数据
                    var response = await _httpClient.GetAsync($"{BaseUrl.SlyUrl}WorkShop/GetAll");
                    var json = await response.Content.ReadAsStringAsync();
                    var list = JsonConvert.DeserializeObject<ApiResult<List<SLY_WORKSHOP_MANAGEMENTMODEL>>>(json);
                    var CdataDictList = list.ResultData.Select(item => new DataDictionary
                    {
                        ID = YitIdHelper.NextId().ToString(),
                        Key = item.ID,
                        Value = item.WORKSHOP_NAME,
                        Type = "车间列表",
                        CreatedUserName = "admin",
                        CreatedTime = DateTime.Now,
                        IsDeleted = item.ISDELETE
                    }).ToList();
                #endregion

                #region httpclint抓取供应商数据
                var response1 = await _httpClient.GetAsync($"{BaseUrl.SlyUrl}Supplier/GetSupplier");
                var json1 = await response1.Content.ReadAsStringAsync();
                var list1 = JsonConvert.DeserializeObject<ApiResult<List<SLY_SUPPLIER_MANAGEMENTMODEL>>>(json1);
                var SdataDictList1 = list1.ResultData.Select(item => new DataDictionary
                {
                    ID = YitIdHelper.NextId().ToString(),
                    Key = item.ID,
                    Value = item.SUPPLIER_NAME,
                    Type = "供应商",
                    CreatedUserName = "admin",
                    CreatedTime = DateTime.Now,
                    IsDeleted = item.ISDELETE
                }).ToList();
                #endregion

                #region httpclint抓取设备类型数据
                /*var response2 = await _httpClient.GetAsync($"http://localhost:5156/api/DeviceType/Gets");
                var json2 = await response2.Content.ReadAsStringAsync();
                var list2 = JsonConvert.DeserializeObject<ApiResult<List<DeviceType>>>(json2);
                var SdataDictList2 = list2.ResultData.Select(item => new DataDictionary
                {
                    ID = YitIdHelper.NextId().ToString(),
                    Key = item.ID,
                    Value = item.Name,
                    Type = "设备类型",
                    CreatedUserName = "admin",
                    CreatedTime = DateTime.Now,
                    IsDeleted = item.IsDeleted
                }).ToList();*/
                #endregion

                #region httpclint抓取用户信息数据
                var response3 = await _httpClient.GetAsync($"http://localhost:5265/api/User");
                var json3 = await response3.Content.ReadAsStringAsync();
                var list3 = JsonConvert.DeserializeObject<ApiResult<List<UserDto>>>(json3);
                var SdataDictList3 = list3.ResultData.Select(item => new DataDictionary
                {
                    ID = YitIdHelper.NextId().ToString(),
                    Key = item.Id.ToString(),
                    Value = item.UserName,
                    Type = "用户信息",
                    CreatedUserName = "admin",
                    CreatedTime = DateTime.Now,
                    IsDeleted = item.IsActive
                }).ToList();
                #endregion











                var data = new List<DataDictionary>();
                data.AddRange(CdataDictList);
                data.AddRange(SdataDictList1);
                data.AddRange(SdataDictList3);
                #region 替换数据
                var dbList = await _db.Queryable<DataDictionary>().ToListAsync();
                // 以 Type+Key 作为唯一标识
                var newSet = data.ToDictionary(x => x.Type + "_" + x.Key);
                var dbSet = dbList.ToDictionary(x => x.Type + "_" + x.Key);

                // 需要插入的
                var toInsert = data
                    .Where(x => !dbSet.ContainsKey(x.Type + "_" + x.Key))
                    .ToList();

                // 需要更新的
                var toUpdate = data
                    .Where(x => dbSet.ContainsKey(x.Type + "_" + x.Key))
                    .ToList();

                // 需要删除的
                var toDelete = dbList
                    .Where(x => !newSet.ContainsKey(x.Type + "_" + x.Key))
                    .ToList();
                await _db.Ado.BeginTranAsync();
                // 批量插入
                if (toInsert.Any())
                    await _db.Insertable(toInsert).ExecuteCommandAsync();

                // 批量更新
                if (toUpdate.Any())
                    await _db.Updateable(toUpdate).ExecuteCommandAsync();

                // 批量删除
                if (toDelete.Any())
                    await _db.Deleteable(toDelete).ExecuteCommandAsync();
                await _db.Ado.CommitTranAsync();
                #endregion
                await SetRedisDict();

                return Ok("数据更新成功");
            }
            catch (Exception ex)
            {
                await _db.Ado.RollbackTranAsync();
                // 记录日志，不更新
                throw new("数据字典更新失败",ex); ;
            }












        }

        /// <summary>
        /// 删除指定类型的数据字典
        /// </summary>
        /// <param name="type">要删除的数据类型</param>
        private async Task DeleteDictByType(string type)
        {
            try
            {
                // 1. 删除Redis中该类型的缓存
                await _redisService.RemoveDictionaryAsync(type); // 假设RemoveDictionaryAsync支持type参数
                // 2. 延迟后再清理一次Redis（防止缓存穿透）
                await Task.Run(async () =>
                {
                    await Task.Delay(500);
                    await _redisService.RemoveDictionaryAsync(type);
                });
            }
            catch (Exception ex)
            {
                Console.WriteLine($"删除{type}类型数据时出错: {ex.Message}");
                throw;
            }
        }
        /// <summary>
        /// 添加数据字典到Redis
        /// </summary>
        /// <exception cref="Exception"></exception>
        private async Task<int> SetRedisDict()
        {
            var failedTypes = new List<string>();
            var dbItems =  _mesRepository.GetList();
            var groupedDict = dbItems.GroupBy(x => x.Type);
           
                //存储redis
                foreach (var group in groupedDict)
                {
                    try
                    {
                        //先删除该Type的Redis字典
                        await DeleteDictByType(group.Key);
                        // 为每个Type创建独立的Redis字典存储
                        var dict = group.ToDictionary(x => x.Key, x => x.Value);
                        await _redisService.SetDictionaryAsync(
                            group.Key,
                            dict,
                            expiry: TimeSpan.FromHours(1) + TimeSpan.FromMinutes(new Random().Next(5))
                        );
                    }
                    catch (Exception ex)
                    {
                        // 获取当前失败的type（从循环变量捕获）
                        failedTypes.Add(group.Key);
                        // 记录详细日志
                        Console.WriteLine($"同步Redis失败，type={group.Key}，原因：{ex.Message}");
                    }
                }

                //处理失败的type
                if (failedTypes.Any())
                {
                    //异常补偿
                    foreach (var failedType in failedTypes)
                    {
                        // 尝试重新同步该type
                        try
                        {
                        //删除该type的Redis字典
                            await DeleteDictByType(failedType);
                            var dict = dbItems.Where(x => x.Type == failedType).ToDictionary(x => x.Key, x => x.Value);
                             await _redisService.SetDictionaryAsync(
                            failedType,
                            dict,
                            //加个随机值，防止缓存穿透
                            expiry: TimeSpan.FromHours(1) + TimeSpan.FromMinutes(new Random().Next(5))
                        );
                            Console.WriteLine($"重新同步Redis成功，type={failedType}");
                        }
                        catch (Exception ex)
                        {}
                    }
                }


                Console.WriteLine("存储Redis成功");
                return 200;
        }


        /// <summary>
        /// 读取Redis数据字典
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> GetDict(string type)
        {
            var dict = await _redisService.GetDictionaryAsync<string>(type);
            return Ok(dict);
        }

    }


}
